import sys
import threading
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

# 帮我们直接运行此文件时，可以加载到上级目录的ui包
# 注意，需要放在导入ui包的前面
sys.path.append("../")

from ui.Ui_serial_assist_widget import Ui_SerialAssistWidget
from views.serial_setting_dialog import SerialSettingDialog
from drivers.driver_serial import *
from common.utils import *


class SerialAssistWidget(QWidget):
    # 创建信号对象
    msg_signal = pyqtSignal(str)
    def __init__(self, parent=None):
        super().__init__(parent)
        # 实例化ui模块对象，调用setupUi()方法
        self.ui = Ui_SerialAssistWidget()
        self.ui.setupUi(self)
        
        self.resize(1200, 600) # 设置窗口大小
        
        # 实例属性
        self.devices = []
        self.sd: SerialDevice = None

        # 初始化UI界面
        self.init_ui()
        
        # 扫描设备
        self.refresh_devices()

    def init_ui(self):
        # 按钮信号和槽函数绑定
        self.ui.btn_setting.clicked.connect(self.btn_setting_slot) # 设置按钮
        self.ui.btn_refersh.clicked.connect(self.refresh_devices)  # 刷新按钮
        self.ui.btn_connect.clicked.connect(self.btn_connect_slot) # 连接设备按钮
        self.ui.btn_send.clicked.connect(self.btn_send_slot) # 发送数据按钮
        
        # 清空按键
        self.ui.pushButton_3.clicked.connect(self.ui.edit_recv.clear) 
        self.ui.pushButton_4.clicked.connect(self.ui.edit_send.clear)
        
        # 自定义信号和槽绑定
        self.msg_signal.connect(self.show_msg)

    def update_connect_ui(self):
        """连接状态界面更新"""
        if self.sd is not None:
            # 当前已连接
            self.ui.btn_connect.setText("断开连接（已连接）")
            self.ui.label_status.setPixmap(QPixmap(":/icon/connect"))
        else:
            # 当前未连接
            self.ui.btn_connect.setText("连接设备")
            self.ui.label_status.setPixmap(QPixmap(":/icon/disc"))

    def refresh_devices(self):
        # 刷新设备列表
        print("刷新设备列表")
        self.devices = scan_serial_ports()
        print(self.devices)
        ports_names = [items[1] for items in self.devices]
        print(ports_names)
        # 清空下拉框列表
        self.ui.cb_device.clear()
        # 添加选项
        self.ui.cb_device.addItems(ports_names)
        
    
    def show_msg(self, msg):
        print("接收到子线程的信号")
        # msg移除末尾的换行符 msg.rstrip()   
        self.ui.edit_recv.append(msg.rstrip())
    
    def receive_data(self):
        try:
            print("子线程开始接收数据")
            while True:
                # data = self.sd.read(5)
                data = self.sd.readline()
                if data:
                    msg = decode_data(data)
                    print(msg)
                    # 发送信号
                    self.msg_signal.emit(msg)
                else:
                    break
        except Exception as e:
            print(e)
    
    def btn_connect_slot(self):
        print("连接按钮被点击")
        
        # 如果串口已经连接，先关闭
        if self.sd is not None:
            self.sd.close()
            self.sd = None
            self.update_connect_ui()
            return # 结束操作

        # 获取串口设备名称
        device = self.devices[self.ui.cb_device.currentIndex()]
        print(device[0])
        # 获取波特率，转换为int类型
        baudrate = int(self.ui.cb_baud.currentText())
        print(baudrate)
        self.sd = SerialDevice(device[0], baud_rate=baudrate, timeout=None)  # 替换为您的串口名称、波特率和超时时间
        if not self.sd.open():
            print("连接失败")
            self.sd = None
            self.update_connect_ui()
            return
        
        print("连接成功, 等待接收数据")
        self.update_connect_ui()
        
        # 创建子线程接收数据，同时设置为守护线程
        self.thread = threading.Thread(target=self.receive_data, daemon=True)
        # 启动子线程
        self.thread.start() 

    def btn_send_slot(self):
        print("发送按钮被点击")
        if self.sd is None:
            print("请先连接设备")
            QMessageBox.warning(self, "警告", "请先连接设备")   
            return
        
        text = self.ui.edit_send.toPlainText()
        if text == "":
            print("请先输入要发送的数据")
            QMessageBox.warning(self, "警告", "请先输入要发送的数据")
            return
    
        self.sd.write(f"{text}\n".encode())  # 发送数据

    def btn_setting_slot(self):
        print("设置按钮被点击")
        """设置按钮的槽函数"""
        # 打开设置对话框
        dialog = SerialSettingDialog()
        
        # 对话框信号和槽连接
        dialog.setting_signal.connect(self.setting_dialog_slot)

        dialog.exec_()

    def setting_dialog_slot(self, baudrate, data_bits):
        print(baudrate, data_bits)
        # 设置下拉框内容
        self.ui.cb_baud.setCurrentIndex(self.ui.cb_baud.findText(baudrate))
        
if __name__ == "__main__":
    app = QApplication(sys.argv)

    w = SerialAssistWidget()
    w.show()

    sys.exit(app.exec_())
